﻿Imports System.ComponentModel

Public Class DataUploadForm

    Private _pi As ProjectItem

    Private _LoadCancled As Boolean = True

    '当前是否正在上传数据
    Private _isUploading As Boolean = False

    Private _isTest As Boolean = True

    '历史数据的前半页长度（标志）
    Private Const halfPage1 As Byte = 1
    '历史数据的后半页长度（标志）
    Private Const halfPage2 As Byte = 2

    '后台数量上传周期
    Private m_backgroundInteval As Integer = 1 * 100        '6秒



    Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click
        Me.Close()
    End Sub

    Private Sub btnUpload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpload.Click
        If Me.btnUpload.Text = "取消" Then
            DoCancel()
            Me.btnUpload.Text = "上传"
            Me.btnExit.Enabled = True

            Me.lblTimeText("")
            Exit Sub
        End If

        If checkValidate() = False Then
            Exit Sub
        End If

        Dim dt As DateTime
        dt = Me.dtpFrom.Value

        Me.btnUpload.Text = "取消"
        Me.btnExit.Enabled = False
        Me.ListView1.Enabled = False
        Me.dtpFrom.Enabled = False
        Me.dtpTo.Enabled = False
        Me.pbUpload.Value = 0
        Me.pbUpload.Visible = True


        BackgroundWorker1 = New BackgroundWorker

        AddHandler BackgroundWorker1.DoWork, AddressOf BackgroundWorker1_DoWork
        AddHandler BackgroundWorker1.RunWorkerCompleted, AddressOf BackgroundWorker1_RunWorkerCompleted
        AddHandler BackgroundWorker1.ProgressChanged, AddressOf BackgroundWorker1_ProgressChanged
        BackgroundWorker1.WorkerSupportsCancellation = True
        BackgroundWorker1.WorkerReportsProgress = True

        Me.BackgroundWorker1.RunWorkerAsync()
    End Sub


    ''' <summary>
    ''' 取消上传
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub DoCancel()
        _LoadCancled = True

        Me.btnUpload.Enabled = False
        Me.lblTimeText("正在取消")

        Me.BackgroundWorker1.CancelAsync()
        Application.DoEvents()
        Me.BackgroundWorker1.Dispose()

        'While BackgroundWorker1.IsBusy
        '    Me.BackgroundWorker1.CancelAsync()
        '    Application.DoEvents()
        '    System.Threading.Thread.Sleep(100)
        '    Application.DoEvents()
        'End While

        Me.lblTimeText("")
        'Me.btnUpload.Enabled = True
        Me.ListView1.Enabled = True
        Me.dtpFrom.Enabled = True
        Me.dtpTo.Enabled = True
        Me.pbUpload.Visible = False
    End Sub

    ''' <summary>
    ''' 检查输入数据的合法性
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function checkValidate() As Boolean
        Dim tip As String

        '检查时间范围
        If Me.dtpTo.Value <= Me.dtpFrom.Value Then
            tip = "终止时间 必须大于 起始时间。"
            msg.ShowWarning(tip)
            Me.dtpTo.Focus()
            Return False
        End If

        '检查设备是否选择
        Dim bFound As Boolean = False
        For Each item As ListViewItem In Me.ListView1.Items
            If item.Checked Then
                bFound = True
                Exit For
            End If
        Next
        If Not bFound Then
            tip = "请选择要上传历史数据的设备。"
            msg.ShowWarning(tip)
            Me.ListView1.Focus()
            Return False
        End If
        Return True

    End Function

#Region "lblTimeText"

    Private Delegate Sub lblTimeTextHandler(ByVal text As String)

    Private Sub lblTimeText(ByVal text As String)
        If Me.InvokeRequired Then
            Dim d As New lblTimeTextHandler(AddressOf _lblTimeText)
            Me.Invoke(d, New Object() {text})
        Else
            _lblTimeText(text)
        End If
    End Sub

    Private Sub _lblTimeText(ByVal text As String)
        Me.lblTime.Text = text
        Me.lblTime.Refresh()
    End Sub

#End Region

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) 'Handles BackgroundWorker1.RunWorkerCompleted
        For i As Integer = 1 To 10
            System.Threading.Thread.Sleep(100)
            Application.DoEvents()
        Next

        If Me.lblTime.Text <> "上传结束" Then
            'Me.lblTimeText("")
        End If

        Me.pbUpload.Visible = False
        Me.btnUpload.Text = "上传"
        Me.btnUpload.Enabled = True
        Me.btnExit.Enabled = True
        Me.ListView1.Enabled = True
        Me.dtpFrom.Enabled = True
        Me.dtpTo.Enabled = True
    End Sub

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) 'Handles BackgroundWorker1.DoWork
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        DoWork(worker)
    End Sub

    ''' <summary>
    ''' 开始后台上传
    ''' </summary>
    ''' <param name="worker"></param>
    ''' <remarks></remarks>
    Private Sub DoWork(ByVal worker As BackgroundWorker)
        Dim dt As DateTime
        dt = Me.dtpFrom.Value

        _LoadCancled = False

        PowerTimeClass.ClearBuffer()

        lblTimeText("")

        Try
            Upload(worker)
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
            Me.lblTimeText("通讯失败")
            Exit Sub
        End Try

        If worker.CancellationPending Then
            Me.lblTimeText("上传取消")
        Else
            lblTimeText("上传结束")
        End If

    End Sub
 
    ''' <summary>
    ''' 调整上传日期(使其为(HIST_SAVE_INTERVAL_TIME*HIST_COUNT_EACH_PAGE )秒的整数倍)
    ''' </summary>
    ''' <param name="dt"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function DateAdjust(ByVal dt As DateTime) As DateTime
        '当天0点至dt的秒数
        Dim s As Integer
        s = dt.Second + dt.Minute * 60 + dt.Hour * 3600

        Return dt.AddSeconds(0 - s Mod (HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE))
    End Function


    ''' <summary>
    ''' 下一页数据的时间
    ''' </summary>
    ''' <param name="dt"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function GetNextDatetime(ByVal dt As DateTime) As DateTime
        dt = dt.AddSeconds(HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE)
        Return dt
    End Function

    Private Delegate Function GetListViewItemHandler() As IList(Of ListViewItem)
    Private Function GetListViewItem()
        If Me.InvokeRequired Then
            Dim d As New GetListViewItemHandler(AddressOf _GetListViewItem)
            Return Me.Invoke(d)
        Else
            Return _GetListViewItem()
        End If
    End Function

    Private Function _GetListViewItem() As IList(Of ListViewItem)
        Dim m_list As IList(Of ListViewItem) = New List(Of ListViewItem)
        For Each lvi As ListViewItem In Me.ListView1.Items
            If lvi.Checked = True Then
                m_list.Add(lvi)
            End If
        Next
        Return m_list
    End Function
 

    ''' <summary>
    ''' 上传历史数据
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Upload(ByVal worker As BackgroundWorker)
        Dim cur_netid As Byte
        Dim cur_ProjectId As String
        Dim netidList As IList(Of Byte) = New List(Of Byte)

        netidList.Clear()

        For Each lvi As ListViewItem In GetListViewItem()

            cur_netid = CType(lvi.Tag, RefTypeItem).NetId
            cur_ProjectId = CType(lvi.Tag, RefTypeItem).ProjectID

            '过滤掉系统设备的上传过程
            If netidList.Contains(cur_netid) = True Then
                Continue For
            End If

            netidList.Add(cur_netid)

            If worker.CancellationPending Then
                Debug.WriteLine("################" + worker.GetHashCode().ToString() + " Exit0")
                Exit For
            End If


            PowerTimeClass.ClearBuffer()

            '读取掉电现场数据
            Dim dic As IDictionary(Of Integer, DateTime)
            dic = PowerTimeClass.GetHistoryDataYearMonth(cur_netid) '获取当前系统已经写入历史记录的时间段信息

            If dic Is Nothing Then
                Continue For
            End If


            If worker.CancellationPending Then
                Debug.WriteLine("################" + worker.GetHashCode().ToString() + " Exit1")
                Exit For
            End If

            Dim dt As DateTime

            Dim dtCurrent As DateTime
            'dtCurrent = Me.dtpTo.Value ' COMHelper.Instance.getCurrentTime(cur_netid)
            dtCurrent = COMHelper.Instance.getCurrentTime(cur_netid)
            If dtCurrent = DateTime.MinValue Then
                '读取控制器时间失败
                dtCurrent = COMHelper.Instance.getCurrentTime(cur_netid)
                If dtCurrent = DateTime.MinValue Then
                    'Exit Sub
                    Continue For
                End If
            End If

            dtCurrent = dtCurrent.AddSeconds(-1 * HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE - 20) '不读取当前正在写入的页面,防止一些尚未被写入的数据被写入

            If worker.CancellationPending Then
                Debug.WriteLine("################" + worker.GetHashCode().ToString() + " Exit2")
                Exit For
            End If


            '-----------------------------------
            '计算总进度
            Dim totalProgress As Integer = 0
            Dim currentProgress As Integer = 0
            For Each kv As KeyValuePair(Of Integer, DateTime) In dic

                dt = kv.Value

                If dt >= Me.dtpTo.Value OrElse dt.AddDays(1) <= Me.dtpFrom.Value Then
                    '历史数据的时间不在选定的时间范围内
                    Continue For
                End If

                For j As Integer = 0 To HIST_USEDPAGECOUNT_EACHAREA - 1
                    dt = kv.Value.AddSeconds(j * HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE)
                    If dt > dtCurrent OrElse dt > Me.dtpTo.Value Then
                        '超过当前时间或超过需要上传的终止时间
                        Exit For
                    End If

                    If dt < Me.dtpFrom.Value Then
                        '尚未达到需要上传的起始时间
                        Continue For
                    End If

                    '是否在掉电期间
                    If PowerTimeClass.HistoryDataValidate(cur_netid, dt) = False Then
                        '掉电期间的无效数据，不上传
                        Continue For
                    End If

                    totalProgress += 1
                Next j
            Next
            '-----------------------------------


            Dim pageIndex As Integer = 0

            '循环处理所有历史日期的数据
            For Each kv As KeyValuePair(Of Integer, DateTime) In dic
                pageIndex = kv.Key * HIST_PLANPAGECOUNT_EACHAREA

                If worker.CancellationPending Then
                    Debug.WriteLine("################" + worker.GetHashCode().ToString() + " Exit3")
                    Exit For
                End If

                dt = kv.Value

                If dt >= Me.dtpTo.Value OrElse dt.AddDays(1) <= Me.dtpFrom.Value Then
                    '历史数据的时间不在选定的时间范围内
                    Continue For
                End If

                Dim dtUpdatedDate As DataTable

                dtUpdatedDate = GetHistory(cur_ProjectId, cur_netid, dt)



                '循环上传某天的所有历史数据
                For i As Integer = 0 To HIST_USEDPAGECOUNT_EACHAREA - 1

                    Application.DoEvents()
                    If worker.CancellationPending Then
                        Debug.WriteLine("################" + worker.GetHashCode().ToString() + " Exit4")
                        Exit For
                    End If

                    dt = kv.Value.AddSeconds(i * HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE)

                    If dt > dtCurrent OrElse dt > Me.dtpTo.Value Then
                        '超过当前时间或超过需要上传的终止时间
                        Exit For
                    End If

                    If dt < Me.dtpFrom.Value Then
                        '尚未达到需要上传的起始时间
                        Continue For
                    End If

                    '是否在掉电期间
                    If PowerTimeClass.HistoryDataValidate(cur_netid, dt) = False Then
                        '掉电期间的无效数据，不上传
                        Continue For
                    End If

                    '是否已经上传
                    Dim filter As String
                    filter = String.Format("iHour={0} and iMinute={1} and iSecond={2}", dt.Hour, dt.Minute, dt.Second)
                    If dtUpdatedDate.Select(filter).Length = 0 Then
                        '历史数据未上传

                        If worker.CancellationPending Then
                            Debug.WriteLine("################" + worker.GetHashCode().ToString() + " Exit5")
                            Exit For
                        End If

                        Me.lblTimeText(String.Format("上传{0}号设备数据,正在上传时间: {1}", cur_netid, UtilityClass.GetDateString(dt)))

                        '上传历史数据
                        uploadHour(cur_ProjectId, cur_netid, pageIndex + i, dt)
                        WaitFor()
                    End If

                    '报告进度
                    currentProgress += 1
                    Me.BackgroundWorker1.ReportProgress(currentProgress / totalProgress * 100)
                Next
            Next
        Next
    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs)
        Me.pbUpload.Value = e.ProgressPercentage
    End Sub


    Private Shared _FailCount As Integer = 0

    ''' <summary>
    ''' 上传指定设备、指定时间（年月日小时）的历史数据
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <param name="indexPage"></param>
    ''' <param name="dt"></param>
    ''' <remarks></remarks>
    Public Shared Sub uploadHour(ByVal ProjectId As String, ByVal netID As Byte, ByVal indexPage As Integer, ByVal dt As DateTime)
        Debug.WriteLine("************ indexPage=" & indexPage)

        Dim buf(511) As Byte
        Dim b1() As Byte

        '历史数据页的前255字节
        b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, indexPage, halfPage1)
        If b1 Is Nothing Then
            '_FailCount += 1
            'If _FailCount > 5 Then
            '    Throw New Exception(ControlChars.NewLine & String.Format("(上传时间：{0})", dt.ToString("yyyy-MM-dd HH:mm:ss")))
            'End If
            Exit Sub
        Else
            _FailCount = 0
        End If
        b1.CopyTo(buf, 0)


        '上半页数据长度
        Dim len As Integer = b1.Length

        '历史数据页的后255字节
        b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, indexPage, halfPage2)
        If b1 Is Nothing Then
            '_FailCount += 1
            'If _FailCount > 5 Then
            '    Throw New Exception(ControlChars.NewLine & String.Format("(上传时间：{0})", dt.ToString("yyyy-MM-dd HH:mm:ss")))
            'End If
            Exit Sub
        Else
            _FailCount = 0
        End If

        b1.CopyTo(buf, len)

        HistoryDataClass.DealData(dt, buf, ProjectId, netID)
        'HistoryDataClass.DealFinish(ProjectId, dt, netID)
    End Sub
    'finish
    ''' <summary>
    ''' 获取指定年月已经上传的历史数据的记录
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <param name="dt"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetHistory(ByVal pid As String, ByVal netID As Integer, ByVal dt As DateTime) As DataTable
        Dim strSql As String
        strSql = String.Format("Select * From tbccHistorydata_{0} where netID=? and iYear=? and iMonth=? and iDay=?", Trim(pid).Replace("-", "_"))
        Dim p(3) As SQLite.SQLiteParameter
        For i As Integer = 0 To p.Length - 1
            p(i) = New SQLite.SQLiteParameter()
        Next
        p(0).Value = netID
        p(1).Value = dt.Year
        p(2).Value = dt.Month
        p(3).Value = dt.Day

        Dim ds As DataSet
        ds = SqlHelper.ExecuteDataset(strSql, p)

        Return ds.Tables(0)
    End Function

    ''' <summary>
    ''' 读取指定设备的当前历史数据的年月列表
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetYearMonths(ByVal netID As Byte) As Dictionary(Of Integer, Integer)
        Dim ymList As Dictionary(Of Integer, Integer)

        ymList = PowerTimeClass.GetHistoryDataYearMonth(netID)

        If ymList Is Nothing Then
            ymList = New Dictionary(Of Integer, Integer)
        End If

        Return ymList
    End Function

    ''' <summary>
    ''' 判断是否其它地方正在读取数据
    ''' </summary>
    ''' <remarks></remarks>
    Public Shared Sub WaitFor()
        System.Threading.Thread.Sleep(200)
    End Sub

    Private Sub DataUploadForm_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DoubleClick
        For Each lvi As ListViewItem In Me.ListView1.Items
            If lvi.Checked = True Then
                btnUpload.Enabled = True
                Exit Sub
            End If
        Next

        btnUpload.Enabled = False
    End Sub

    Private Sub DataUploadForm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        Me.BackgroundWorker1.CancelAsync()
        Application.DoEvents()
        Me.BackgroundWorker1.Dispose()
        MyBase.OnClosing(e)
    End Sub


    Private Sub DataUploadForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Me.btnUpload.Enabled = False

        _pi = MainForm.pi

        LoadTime()

        If LoadAllRef() = False Then
            msg.ShowWarning("无法导入设备,请先配置工程设备")
        End If

    End Sub

    Private Function LoadAllRef() As Boolean
        Dim isDevExist As Boolean = False

        Dim dts As New DevTypeService(_pi)
        Dim rts As New RefTypeService(_pi)

        Me.ListView1.Items.Clear()
        Me.ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
        Dim item As ListViewItem


        For Each dti As DevTypeItem In dts.GeDevGroupList()   '设备列表
            isDevExist = True
            Dim devlvg As New ListViewGroup(String.Format("{0}号设备", dti.NetId))
            Me.ListView1.Groups.Add(devlvg)
            devlvg.Tag = dti
            For Each rti As RefTypeItem In rts.GeRefGroupList(dti.NetId) '增加该设备冷库信息
                item = New ListViewItem(rti.RefName, devlvg)
                item.Tag = rti
                ListView1.Items.Add(item)
            Next
        Next
        Return isDevExist
    End Function

    Private Sub LoadTime()
        Me.dtpTo.Value = Now.ToShortDateString()
        Me.dtpFrom.Value = dtpTo.Value
    End Sub

    Private Sub ListView1_ItemCheck(ByVal sender As Object, ByVal e As System.Windows.Forms.ItemCheckEventArgs) Handles ListView1.ItemCheck
        'For Each lvi As ListViewItem In Me.ListView1.Items
        '    If lvi.Checked = True Then
        '        btnUpload.Enabled = True
        '        Exit Sub
        '    End If
        'Next

        'btnUpload.Enabled = False
    End Sub

End Class